package com.sojson.util;

import java.io.ByteArrayOutputStream;

import com.sojson.config.exception.TransException;

import cn.hutool.core.io.checksum.crc16.CRC16Modbus;

public class HexUtil {

    public static String str2HexStr(String str) {
        char[] chars = "0123456789ABCDEF".toCharArray();
        StringBuilder sb = new StringBuilder("");
        byte[] bs = str.getBytes();

        for (int i = 0; i < bs.length; i++) {
            int bit = (bs[i] & 0x0f0) >> 4;
            sb.append(chars[bit]);
            bit = bs[i] & 0x0f;
            sb.append(chars[bit]);
        }
        return sb.toString();
    }

    public static String hexStr2Str(String hexStr) {
        String str = "0123456789ABCDEF";
        char[] hexs = hexStr.toCharArray();
        byte[] bytes = new byte[hexStr.length() / 2];

        for (int i = 0; i < bytes.length; i++) {
            int n = str.indexOf(hexs[(2 * i)]) * 16;
            n += str.indexOf(hexs[(2 * i + 1)]);
            bytes[i] = ((byte)(n & 0xFF));
        }
        return new String(bytes);
    }

    /**
     * 对数组的每一位数转16进制,如果不满两位补0,并将所有数拼接成一个字符串
     *
     * @param bytes
     * @return
     */
    public static String bytesToHexString(byte[] bytes) {
        String result = "";
        for (int i = 0; i < bytes.length; i++) {
            String hexString = Integer.toHexString(bytes[i] & 0xFF);
            if (hexString.length() == 1) {
                hexString = '0' + hexString;
            }
            result = result + hexString.toUpperCase();
        }
        return result;
    }

    /**
     * 将一个十六进制字符串转为一个十进制数字(byte类型),这个十六进制字符串为两位(不足两位补0),然后拆成两个byte数字传进来
     *
     * @param src0
     * @param src1
     * @return
     */
    private static byte uniteBytes(byte src0, byte src1) {
        byte _b0 = Byte.decode("0x" + new String(new byte[] {src0})).byteValue();
        _b0 = (byte)(_b0 << 4);
        byte _b1 = Byte.decode("0x" + new String(new byte[] {src1})).byteValue();
        byte ret = (byte)(_b0 | _b1);
        return ret;
    }

    /**
     * 将每两位十六进制字符串转为一个十进制字节
     *
     * @param src
     * @return
     */
    public static byte[] hexString2Bytes(String src) {
        int len = src.length() / 2;
        byte[] ret = new byte[len];
        byte[] tmp = src.getBytes();
        for (int i = 0; i < len; i++) {
            ret[i] = uniteBytes(tmp[(i * 2)], tmp[(i * 2 + 1)]);
        }
        return ret;
    }

    public static String StringToAsciiString(String content) {
        String result = "";
        int max = content.length();
        for (int i = 0; i < max; i++) {
            char c = content.charAt(i);
            String b = Integer.toHexString(c);
            result = result + b;
        }
        return result;
    }

    public static String AsciiStringToString(String content) {
        String result = "";
        int length = content.length() / 2;
        for (int i = 0; i < length; i++) {
            String c = content.substring(i * 2, i * 2 + 2);
            int a = hexStringToAlgorism(c);
            char b = (char)a;
            String d = String.valueOf(b);
            result = result + d;
        }
        return result;
    }

    public static int hexStringToAlgorism(String hex) {
        hex = hex.toUpperCase();
        int max = hex.length();
        int result = 0;
        for (int i = max; i > 0; i--) {
            char c = hex.charAt(i - 1);
            int algorism = 0;
            if ((c >= '0') && (c <= '9')) {
                algorism = c - '0';
            } else {
                algorism = c - '7';
            }
            result = (int)(result + Math.pow(16.0D, max - i) * algorism);
        }
        return result;
    }

    public static String getInfoBuff(byte[] buff, int count) {
        byte[] temp = new byte[count];
        for (int i = 0; i < count; i++) {
            temp[i] = buff[i];
        }
        return new String(temp);
    }

    /**
     * 将两个字节数组合成一个字节数组
     *
     * @param byte_1
     * @param byte_2
     * @return
     */
    public static byte[] byteMerger(byte[] byte_1, byte[] byte_2) {
        byte[] byte_3 = new byte[byte_1.length + byte_2.length];
        System.arraycopy(byte_1, 0, byte_3, 0, byte_1.length);
        System.arraycopy(byte_2, 0, byte_3, byte_1.length, byte_2.length);
        return byte_3;
    }

    public static byte[] byteMerger2(byte[] b1, byte[] b2) {
        return byteMerger(b1, b2);
    }

    /**
     * 将三个字节数组合成一个字节数组
     *
     * @param b1
     * @param b2
     * @param b3
     * @return
     */
    public static byte[] byteMerger3(byte[] b1, byte[] b2, byte[] b3) {
        b1 = byteMerger(b1, b2);
        return byteMerger(b1, b3);
    }

    /**
     * 将四个字节数组合成一个字节数组
     *
     * @param b1
     * @param b2
     * @param b3
     * @return
     */
    public static byte[] byteMerger4(byte[] b1, byte[] b2, byte[] b3, byte[] b4) {
        b1 = byteMerger(b1, b2);
        b1 = byteMerger(b1, b3);
        return byteMerger(b1, b4);
    }

    public static byte[] byteMerger5(byte[] b1, byte[] b2, byte[] b3, byte[] b4, byte[] b5) {
        b1 = byteMerger(b1, b2);
        b1 = byteMerger(b1, b3);
        b1 = byteMerger(b1, b4);
        return byteMerger(b1, b5);
    }

    public static byte[] byteMerger6(byte[] b1, byte[] b2, byte[] b3, byte[] b4, byte[] b5, byte[] b6) {
        b1 = byteMerger(b1, b2);
        b1 = byteMerger(b1, b3);
        b1 = byteMerger(b1, b4);
        b1 = byteMerger(b1, b5);
        return byteMerger(b1, b6);
    }

    public static byte[] byteMerger7(byte[] b1, byte[] b2, byte[] b3, byte[] b4, byte[] b5, byte[] b6, byte[] b7) {
        b1 = byteMerger(b1, b2);
        b1 = byteMerger(b1, b3);
        b1 = byteMerger(b1, b4);
        b1 = byteMerger(b1, b5);
        b1 = byteMerger(b1, b6);
        return byteMerger(b1, b7);
    }

    /**
     * 将字符串转int再转16进制,如果不够4位就补0,然后两位一组分成两个字节并组成一个字节数组
     *
     * @param len
     * @return
     */
    public static byte[] lenarr(String len) {
        String lenHex = Integer.toHexString(Integer.parseInt(len)).toUpperCase();

        if (lenHex.length() == 1) {
            lenHex = "000" + lenHex;
        } else if (lenHex.length() == 2) {
            lenHex = "00" + lenHex;
        } else if (lenHex.length() == 3) {
            lenHex = "0" + lenHex;
        }

        byte l11 = (byte)Integer.valueOf(lenHex.substring(0, 2), 16).intValue();
        byte l12 = (byte)Integer.valueOf(lenHex.substring(2, 4), 16).intValue();

        return new byte[] {l11, l12};
    }

    public static byte[] lenarr2(String len) {
        String lenHex = Integer.toHexString(Integer.parseInt(len)).toUpperCase();

        if (lenHex.length() == 1) {
            lenHex = "0" + lenHex;
        }

        byte l11 = (byte)Integer.valueOf(lenHex.substring(0, 2), 16).intValue();

        return new byte[] {l11};
    }

    public static byte[] str2cbcd(String s) {
        if (s.length() % 2 != 0) {
            s = "0" + s;
        }
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        char[] cs = s.toCharArray();
        for (int i = 0; i < cs.length; i += 2) {
            int high = cs[i] - '0';
            int low = cs[(i + 1)] - '0';
            baos.write(high << 4 | low);
        }
        return baos.toByteArray();
    }

    public static String cbcd2str(byte[] b) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            int h = ((b[i] & 0xFF) >> 4) + 48;
            sb.append((char)h);
            int l = (b[i] & 0xF) + 48;
            sb.append((char)l);
        }
        return sb.toString();
    }

    public static boolean isChinese(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        if ((ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS)
            || (ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS)
            || (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A)
            || (ub == Character.UnicodeBlock.GENERAL_PUNCTUATION)
            || (ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION)
            || (ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS)) {
            return true;
        }
        return false;
    }

    public static String hexString2binaryString(String hexString) {
        if (hexString == null || hexString.length() % 2 != 0) {
            return null;
        }
        String bString = "", tmp;
        for (int i = 0; i < hexString.length(); i++) {
            tmp = "0000" + Integer.toBinaryString(Integer.parseInt(hexString.substring(i, i + 1), 16));
            bString += tmp.substring(tmp.length() - 4);
        }
        return bString;
    }

    public static byte[] sjarr(String shijian) {
        byte b1 = (byte)Integer.valueOf(shijian.substring(0, 2), 16).intValue();
        byte b2 = (byte)Integer.valueOf(shijian.substring(2, 4), 16).intValue();
        byte b3 = (byte)Integer.valueOf(shijian.substring(4, 6), 16).intValue();
        byte b4 = (byte)Integer.valueOf(shijian.substring(6, 8), 16).intValue();
        byte b5 = (byte)Integer.valueOf(shijian.substring(8, 10), 16).intValue();
        byte b6 = (byte)Integer.valueOf(shijian.substring(10, 12), 16).intValue();
        byte[] sjarr = {b1, b2, b3, b4, b5, b6, 13, 10};

        return sjarr;
    }

    public static String temp(String str) {
        Integer s1 = Integer.parseInt(str, 16);
        String s3 = Integer.toBinaryString(s1);
        String s2 = "";
        if (s1 > 128) {
            for (int i = 0; i < s3.length(); i++) {
                if (s3.substring(i, i + 1).equals("0")) {
                    s2 = s2 + "1";
                } else {
                    s2 = s2 + "0";
                }
            }
            return "-" + (Integer.parseInt(s2, 2) + 1);
        }
        return s1.toString();
    }

    public static byte[] temp1(String str, Integer a) {
        Integer s1 = Integer.parseInt(str);
        if (s1 < 0) {
            String s3 = Integer.toBinaryString(s1);
            String s2 = s3.substring(s3.length() - 8, s3.length());
            byte[] param1 = {(byte)Integer.valueOf(Integer.toHexString(a), 16).intValue(), (byte)0xFF,
                (byte)Integer.valueOf(s2, 2).intValue()};
            return param1;
        }
        byte[] param1 = {(byte)Integer.valueOf(Integer.toHexString(a), 16).intValue(), 0, new Byte(str)};
        return param1;
    }

    /**
     * 转为16进制字符串
     *
     * @param nums
     * @return
     */
    public static String toHex(byte[] nums) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < nums.length; i++) {
            String hex = Integer.toHexString(nums[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 转为10进制字节
     *
     * @param nums
     * @return
     */
    public static byte[] parseHex(String nums) {
        if (nums.length() < 1) {
            return null;
        }

        byte[] result = new byte[nums.length() / 2];
        for (int i = 0; i < nums.length() / 2; i++) {
            int high = Integer.parseInt(nums.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(nums.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = ((byte)(high * 16 + low));
        }
        return result;
    }

    /**
     * 转为16进制字符串
     *
     * @param num
     * @return
     */
    public static String toHex(byte num) {
        String hex = Integer.toHexString(num & 0xFF);
        if (hex.length() == 1) {
            hex = '0' + hex;
        }
        return hex.toUpperCase();
    }

    /**
     * 转为16进制字符串
     *
     *
     * @param num
     * @param byteNum   字节数
     * @return
     */
    public static String toHex(int num, int byteNum) {
        String max = "FF";
        StringBuilder multiplier = new StringBuilder();
        for (int i = 0; i < byteNum; i++) {
            multiplier.append(max);
        }
        String hex = Integer.toHexString(num & Integer.parseInt(multiplier.toString(), 16));
        int len = hex.length();
        int lenCount = byteNum * 2;
        if (len == lenCount) {
            return hex;
        }

        StringBuilder str = new StringBuilder();
        char zore = '0';
        int diffe = lenCount - len;
        for (int i = 0; i < diffe; i++) {
            str.append(zore);
        }
        str.append(hex);
        return str.toString().toUpperCase();
    }

    /**
     * 转为10进制字节
     *
     * @param num
     * @return
     */
    public static byte parseHexOne(String num) {
        int high = Integer.parseInt(num.substring(0, 1), 16);
        int low = Integer.parseInt(num.substring(1, 2), 16);
        return ((byte)(high * 16 + low));
    }

    /**
     * 高位转低位
     *
     * @param data
     * @return
     */
    public static String reverse(String data) {
        StringBuilder str = new StringBuilder();
        int len = data.length() / 2;
        for (int i = 0; i < len; i++) {
            str.append(data.substring((len - i - 1) * 2, (len - i) * 2));
        }
        return str.toString();
    }

    /**
     * 计算16进制字符串的和并取模256
     *
     * @param nums
     * @return
     */
    public static String sumHexAndModule(String nums) {
        if (nums.length() < 1) {
            return null;
        }

        int sum = 0;
        for (int i = 0; i < nums.length() / 2; i++) {
            int high = Integer.parseInt(nums.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(nums.substring(i * 2 + 1, i * 2 + 2), 16);
            sum += (high * 16 + low);
        }
        return toHex((byte)(sum % 256));
    }

    /**
     * 计算16进制字符串+0x33
     *
     * @param nums
     * @return
     */
    public static String addThirtyThree(String nums) {
        if (nums.length() < 1) {
            return null;
        }

        String sum = "";
        for (int i = 0; i < nums.length() / 2; i++) {
            int high = Integer.parseInt(nums.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(nums.substring(i * 2 + 1, i * 2 + 2), 16);
            sum += toHex((byte)(high * 16 + low + 0x33));
        }
        return sum;
    }

    /**
     * 计算16进制字符串-0x33
     *
     * @param nums
     * @return
     */
    public static String subtractThirtyThree(String nums) {
        if (nums.length() < 1) {
            return null;
        }

        String sum = "";
        for (int i = 0; i < nums.length() / 2; i++) {
            int high = Integer.parseInt(nums.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(nums.substring(i * 2 + 1, i * 2 + 2), 16);
            sum += toHex((byte)(high * 16 + low - 0x33));
        }
        return sum;
    }

    /**
     * 校验报文长度
     *
     * @param data          数据
     * @param verifyCode    校验码
     */
    public static void dataLenVerify(String data, String verifyCode) {
        dataLenVerify(data, verifyCode, 2);
    }

    /**
     * 校验报文长度
     *
     * @param data          数据
     * @param verifyCode    校验码
     * @param byteNum   字节数
     */
    public static void dataLenVerify(String data, String verifyCode, int byteNum) {
        if (data.length() / 2 != Integer.parseInt(verifyCode, 16)) {
            throw new TransException("数据长度校验失败: " + data);
        }
    }

    /**
     * 校验报文
     *
     * @param data          数据
     * @param verifyCode    校验码
     */
    public static void dataVerify(String data, String verifyCode) {
        dataVerify(data, verifyCode, "68", data.length() - 2 * 2);
    }

    /**
     * 校验报文
     *
     * @param data          数据
     * @param verifyCode    校验码
     * @param startStr      开头字符串
     * @param endIndex      结尾索引
     */
    public static void dataVerify(String data, String verifyCode, String startStr, int endIndex) {
        if (!HexUtil.sumHexAndModule(data.substring(data.indexOf(startStr), endIndex)).equals(verifyCode)) {
            throw new TransException("数据校验失败: " + data);
        }
    }

    /**
     * 校验报文
     *
     * @param data          数据
     * @param verifyCode    校验码
     * @param startStr      开头字符串
     */
    public static void crcVerify(String data, String verifyCode, String startStr) {
        crcVerify(data, verifyCode, startStr, data.length() - 2 * 2);
    }

    /**
     * crcVerify校验报文
     *
     * @param data          数据
     * @param verifyCode    校验码
     * @param startStr      开头字符串
     * @param endIndex      结尾索引
     */
    public static void crcVerify(String data, String verifyCode, String startStr, int endIndex) {
        data = data.substring(data.indexOf(startStr), endIndex);

        if (getCrc(data) != Integer.parseInt(reverse(verifyCode), 16)) {
            throw new TransException("数据校验失败: " + data);
        }
    }

    /**
     * 获取crc值
     *
     * @param data
     * @return
     */
    public static long getCrc(String data) {
        CRC16Modbus crc32 = new CRC16Modbus();
        crc32.update(parseHex(data));
        return crc32.getValue();
    }

}